
use super::room::GameRoom;
use std::marker::Send;
use serde::ser::{Serialize, Serializer, SerializeStruct};
use chess::Point;

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ChessCommand{
    ///玩家匹配成功，组建新的游戏房间。 room_id, black_id, white_id
    NewRoom(u32, u32, u32),

    ///玩家落子。 room_id, player_id, location
    PutPiece(u32, u32, u8),

    ///玩家吃子。 room_id, player_id, location
    KillPiece(u32, u32, u8),

    ///玩家走子。 room_id, user_id, source, target
    MovePiece(u32, u32, u8, u8),

    ///玩家投降。 room_id, user_id
    GiveUp(u32, u32)
}

#[derive(Serialize, Clone, Debug, Eq, PartialEq)]
pub struct ChessResponse{
    pub turn: bool,
    pub operate: String,
    pub board: Vec<Point>,
    pub current: Operation,
}

impl ChessResponse{
    pub fn new(board: Vec<Point>, turn: bool, operate: String, current: Operation) -> ChessResponse{
        ChessResponse{
            turn, operate, board, current
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum  Operation{
    Put(u8),
    Kill(u8),
    Move(u8, u8)
}

impl Serialize for Operation{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer{
        match *self {
            Operation::Put(index) =>{
                let mut put = serializer.serialize_struct("put", 2)?;
                put.serialize_field("type", "put")?;
                put.serialize_field("location", &index)?;
                put.end()
            },
            Operation::Kill(index) => {
                let mut kill = serializer.serialize_struct("kill", 2)?;
                kill.serialize_field("type", "kill")?;
                kill.serialize_field("location", &index)?;
                kill.end()
            },
            Operation::Move(source, target) => {
                let mut map = serializer.serialize_struct("move", 3)?;
                map.serialize_field("type", "move")?;
                map.serialize_field("source", &source)?;
                map.serialize_field("target", &target)?;
                map.end()
            }
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum PlayerResponse{
    MatchPlayer(u32, u32),
    ChessOk(u32, ChessResponse),
    GameOver(u32, String),
    Error(u32, String)
}

impl Serialize for PlayerResponse{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer{
        match *self {
            PlayerResponse::MatchPlayer(id, ref opponent) =>{
                let mut map = serializer.serialize_struct("match", 2)?;
                map.serialize_field("code", "match_ok")?;
                map.serialize_field("opponent", opponent)?;
                map.end()
            },
            PlayerResponse::ChessOk(id, ref response) =>{
                let mut map = serializer.serialize_struct("ok", 2)?;
                map.serialize_field("code", "chess_ok")?;
                map.serialize_field("body", response)?;
                map.end()
            },
            PlayerResponse::GameOver(id, ref message) => {
                let mut map = serializer.serialize_struct("over", 2)?;
                map.serialize_field("code", "game_over")?;
                map.serialize_field("message", message)?;
                map.end()
            },
            PlayerResponse::Error(id, ref message) => {
                let mut map = serializer.serialize_struct("error", 2)?;
                map.serialize_field("code", "chess_error")?;
                map.serialize_field("message", message)?;
                map.end()
            }
        }
    }
}